﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using XCI.Extensions;

namespace XCI.Core
{
    /// <summary>
    /// 列表缓存,线程安全,独占锁
    /// </summary>
    /// <typeparam name="T">元素类型</typeparam>
    public class ListCache<T>
    {
        private readonly static object lockObj = new object();
        private readonly List<T> list = new List<T>();

        /// <summary>
        /// 获取列表元素数量
        /// </summary>
        public int Count
        {
            get { lock (lockObj) { return list.Count; } }
        }

        /// <summary>
        /// 初始化列表缓存
        /// </summary>
        /// <param name="collection">缓存数据</param>
        public void Init(IEnumerable<T> collection)
        {
            if (collection == null) throw new ArgumentNullException(nameof(collection), "请指定缓存数据");
            lock (lockObj)
            {
                list.Clear();
                list.AddRange(collection);
            }
        }

        /// <summary>
        /// 是否存在指定条件的列表项
        /// </summary>
        /// <param name="predicate">查找条件</param>
        /// <returns>存在返回true</returns>
        public bool Contains(Func<T, bool> predicate)
        {
            if (predicate == null) throw new ArgumentNullException(nameof(predicate), "请指定查找条件");
            lock (lockObj)
            {
                return list.Any(predicate);
            }
        }

        /// <summary>
        /// 添加列表项
        /// </summary>
        /// <param name="item">列表元素对象</param>
        public void Add(T item)
        {
            if (item == null) throw new ArgumentNullException(nameof(item), "请指定列表元素对象");
            lock (lockObj)
            {
                list.Add(item);
            }
        }

        /// <summary>
        /// 添加列表项
        /// </summary>
        /// <param name="collection">列表元素对象集合</param>
        public void Add(IEnumerable<T> collection)
        {
            if (collection == null) throw new ArgumentNullException(nameof(collection), "请指定缓存数据");
            lock (lockObj)
            {
                list.AddRange(collection);
            }
        }

        /// <summary>
        /// 设置列表项
        /// </summary>
        /// <param name="item">列表元素对象</param>
        /// <param name="predicate">查找条件</param>
        public bool Set(T item, Func<T, bool> predicate)
        {
            if (item == null) throw new ArgumentNullException(nameof(item), "请指定列表元素对象");
            if (predicate == null) throw new ArgumentNullException(nameof(predicate), "请指定查找条件");
            lock (lockObj)
            {
                var index = list.FindIndex(p => predicate(p));
                if (index > -1)
                {
                    list[index] = item;
                    return true;
                }
                return false;
            }
        }

        /// <summary>
        /// 获取指定条件的第一个匹配项索引
        /// </summary>
        /// <param name="predicate">查找条件</param>
        public int IndexOf(Func<T, bool> predicate)
        {
            if (predicate == null) throw new ArgumentNullException(nameof(predicate), "请指定查找条件");
            lock (lockObj)
            {
                return list.FindIndex(p => predicate(p));
            }
        }

        /// <summary>
        /// 删除列表项
        /// </summary>
        /// <param name="predicate">查找条件</param>
        public void Remove(Func<T, bool> predicate)
        {
            if (predicate == null) throw new ArgumentNullException(nameof(predicate), "请指定查找条件");
            lock (lockObj)
            {
                var items = list.Where(predicate);
                foreach (T i in items)
                {
                    list.Remove(i);
                }
            }
        }

        /// <summary>
        /// 删除列表项
        /// </summary>
        /// <param name="index">索引</param>
        public void Remove(int index)
        {
            lock (lockObj)
            {
                if (index >= 0 && index < list.Count)
                {
                    list.RemoveAt(index);
                }
            }
        }

        /// <summary>
        /// 清空
        /// </summary>
        public void Clear()
        {
            lock (lockObj)
            {
                list.Clear();
            }
        }


        /// <summary>
        /// 获取单个元素
        /// </summary>
        /// <param name="predicate">查找条件</param>
        /// <param name="factory">找不到缓存时创建对象回掉函数,并添加到缓存</param>
        /// <returns>返回第一个符合条件的项,没有找到返回空</returns>
        public T Get(Func<T, bool> predicate, Func<T> factory = null)
        {
            if (predicate == null) throw new ArgumentNullException(nameof(predicate), "请指定查找条件");
            lock (lockObj)
            {
                var d = list.FirstOrDefault(predicate);
                if (d == null && factory != null)
                {
                    d = factory();
                    list.Add(d);
                    return d;
                }
                return default(T);
            }
        }

        /// <summary>
        /// 获取单个元素
        /// </summary>
        /// <param name="index">索引</param>
        /// <param name="factory">找不到缓存时创建对象回掉函数,并添加到缓存</param>
        /// <returns>返回第一个符合条件的项</returns>
        public T Get(int index, Func<T> factory = null)
        {
            lock (lockObj)
            {
                if (index >= 0 && index < list.Count)
                {
                    return list[index];
                }
                else if (factory != null)
                {
                    var d = factory();
                    list.Add(d);
                    return d;
                }
                return default(T);
            }
        }

        /// <summary>
        /// 获取列表
        /// </summary>
        public List<T> GetList()
        {
            lock (lockObj)
            {
                return list.ToList();
            }
        }

        /// <summary>
        /// 获取列表
        /// </summary>
        /// <param name="predicate">查找条件</param>
        public List<T> GetList(Func<T, bool> predicate)
        {
            lock (lockObj)
            {
                return predicate == null ? list.ToList() : list.Where(predicate).ToList();
            }
        }

        /// <summary>
        /// 获取分页列表
        /// </summary>
        /// <param name="pageCondition">分页条件</param>
        /// <param name="predicate">查找条件</param>
        public PagingList<T> GetPageList(BasePageFilter pageCondition, Func<T, bool> predicate)
        {
            if (pageCondition == null) throw new ArgumentNullException(nameof(pageCondition), "请指定分页条件");

            List<T> data = null;
            lock (lockObj)
            {
                data = predicate == null ? list.ToList() : list.Where(predicate).ToList();
            }
            if (!string.IsNullOrEmpty(pageCondition.SortName))
            {
                data.OrderBy(pageCondition.SortName, pageCondition.SortDir);
            }
            var pageIndex = pageCondition.PageIndex;
            var pageSize = pageCondition.PageSize;
            var pageData = data.Skip((pageIndex.Value - 1) * pageSize.Value).Take(pageSize.Value).ToList();
            var plist = new PagingList<T>
            {
                PageIndex = pageIndex.Value,
                PageSize = pageSize.Value,
                Total = data.Count,
                Rows = pageData
            };
            return plist;
        }
    }
}